using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Oops.Xna.Framework.Diagnostics
{
	/// <summary>
	/// Displays Garbage collection information.
	/// </summary>
	public class GCComponent : DrawableGameComponent
	{
		private WeakReference weakReference;
		private int gcCount;
		private string gcCountText = "";

		private SpriteBatch spriteBatch;
		private SpriteFont spriteFont;

		/// <summary>
		/// Initializes a new instance of the <see cref="GCComponent"/> class.
		/// </summary>
		/// <param name="game"><see cref="Microsoft.Xna.Framework.Game"/>that the game component should be attached to.</param>
		public GCComponent(Game game)
			: base(game)
		{
			// The game parameter must be specified.
			if (game == null)
			{
				throw new ArgumentNullException("game");
			}

			// Default property values.
			this.Color = Color.White;
		}

		/// <summary>
		/// Gets or sets the location of the garbage collection count text.
		/// </summary>
		public Vector2 Position { get; set; }

		/// <summary>
		/// Gets or sets the color to use when displaying the garbage collection count.
		/// </summary>
		public Color Color { get; set; }

		/// <summary>
		/// Gets or sets the name of the <see cref="Microsoft.Xna.Framework.Graphics.SpriteFont"/> to use when displaying the garbage collection count.
		/// </summary>
		public string FontAssetName { get; set; }

		#region DrawableGameComponent Members

		protected override void LoadContent()
		{
			// Create the sprite batch.
			this.spriteBatch = new SpriteBatch(this.GraphicsDevice);

			// Get the font asset.
			this.spriteFont = this.Game.GetContent().Load<SpriteFont>(this.FontAssetName);
			
			// Call inherited method.
			base.LoadContent();
		}

		protected override void UnloadContent()
		{
			// Dispose of the sprite batch.
			if (this.spriteBatch != null)
			{
				this.spriteBatch.Dispose();
			}

			// Call inherited method.
			base.UnloadContent();
		}

		#endregion

		#region IGameComponent Members

		public override void Initialize()
		{
			// Update and draw last.
			this.UpdateOrder = int.MaxValue;
			this.DrawOrder = int.MaxValue;

			// Call inherited method.
			base.Initialize();

			// Create the weak reference.
			this.weakReference = new WeakReference(new object());
		}

		#endregion

		#region IUpdateable Members

		public override void Update(GameTime gameTime)
		{
			// Update the garbage collection count
			if (!this.weakReference.IsAlive)
			{
				this.gcCount++;
				// TODO : GC!
				this.gcCountText = this.gcCount.ToString();
				this.weakReference.Target = new object();
			}

			// Call inherited method.
			base.Update(gameTime);
		}

		#endregion

		#region IDrawable Members

		public override void Draw(GameTime gameTime)
		{
			// Draw the garbage collection count.
			this.spriteBatch.Begin(
				SpriteBlendMode.AlphaBlend,
				SpriteSortMode.Immediate,
				SaveStateMode.SaveState);
			this.spriteBatch.DrawString(
				this.spriteFont,
				this.gcCountText,
				this.Position,
				this.Color);
			this.spriteBatch.End();

			// Call inherited method.
			base.Draw(gameTime);
		}

		#endregion
	}
}